#include "dbworker.h"
#include "my_defs.h"

#include <QTreeView>
#include <QSqlDatabase>
#include "appmanager.h"
#include "treemodel.h"

DBWorker::DBWorker(QObject *parent)
    :QObject(parent),
      mTabModel(NULL),
      mTreeModel(NULL),
      mDbName(""),
      mCurRec(-1),
      mSearchRowsCount(0)
{
    mIsDbLoaded = false;
}

bool DBWorker::openDb(const QString dbName)
{
    if (dbName.isEmpty())
    {
        LOG( "DBWorker::openDb", "Передано порожню адресу до БД!", "" );
        return false;
    }
    else
    {
        if (!QFile::exists(dbName))
        {
            LOG( "DBWorker::openDb", QString("Не знайдено файлу бази: %1").arg(mDbName), "" );
            return false;
        }
        else
        {   // All right w/ DB, opening it
            mDbName = dbName;
            mWorkDB = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", "MainConnection"));
            mWorkDB->setDatabaseName(mDbName);

            if (!mWorkDB->open())
            {
                LOG( "DBWorker::openDb", QString("Не вдалося відкрити базу: %1")
                     .arg(mWorkDB->lastError().text()), "" );
//                 TODO: check if needed to close it
//                 mWorkDB->close();
                return false;
            }
            else
            {
                // DB is opened
                LOG( "DBWorker::openDb", "База успішно відкрита!", "" );

                freeModels();
                createModels();

                mIsDbLoaded = true;
            }
        }
    }
    return true;
}

void DBWorker::closeCurrentDb()
{
    freeModels();
    if (mWorkDB!=NULL)
    {
        delete mWorkDB;
        mWorkDB = NULL;
    }
    QSqlDatabase::removeDatabase("MainConnection");

    mIsDbLoaded = false;

    emit needRefresh();
}

bool DBWorker::createDB(QString dbName, QString createText)
{
    if (QFile::exists(dbName))
    {
        LOG( "DBWorker::createDB", QString("Файл БД вже існує: %1!").arg(dbName), "" );
        return false;
    }
    else
    {
        mWorkDB = new QSqlDatabase( QSqlDatabase::addDatabase("QSQLITE",  "CreateConnection") );
        mWorkDB->setDatabaseName(dbName);

        if (!mWorkDB->open())
        {
            LOG( "DBWorker::createDB", "Не вдалося створити базу:", mWorkDB->lastError().text() );
            return false;
        }
        else
        {
            LOG( "DBWorker::createDB", "Файл БД створено.", dbName);
            QSqlQuery query(createText, *mWorkDB);
            query.prepare(createText);
            if(!query.exec())
            {
                LOG( "DBWorker::createDB, query.exec",
                     QString("Проблема з виконанням запиту "
                             "<font face='DejaVu Sans Mono'>%1</font>.<br/>"
                             "Помилка: <font face='DejaVu Sans Mono'>%2</font>")
                     .arg(query.lastQuery())
                     .arg(query.lastError().text()), "" );
                // TODO: check if I must return here
                // return false;
            }
            query.clear(); // check it!!!
        }
    }

    openDb(dbName);

    emit needRefresh();
    return true;
}

bool copyFile(const QString& sourceFile, const QString& destinationFile)
{
    bool result = QFile::copy(sourceFile, destinationFile);
    return result;
}

bool DBWorker::saveDbAs(const QString newDbName)
{
    bool res =  copyFile(appManager->dbWorker()->dbName(), newDbName);
    if (!res)
    {
        LOG("DBWorker::saveDbAs", "Не вдалося зберегти БД в:", newDbName);
        return false;
    }
    return true;
}

void DBWorker::deleteCurRecord()
{
    if (mCurRec>=0)
    {
        QSqlQuery query(*mWorkDB);
        query.prepare(DELETE_RECORD);
        query.bindValue(":uniqId", mCurRec);
        if(!query.exec())
        {
            LOG( "DBWorker::deleteCurRecord, query.exec",
                 QString("Проблема з виконанням запиту "
                         "<font face='DejaVu Sans Mono'>%1</font>.<br/>"
                         "Помилка: <font face='DejaVu Sans Mono'>%2</font>")
                 .arg(query.lastQuery())
                 .arg(query.lastError().text()), "" );
            mCurRec = -1;
            return;
        }
        query.clear(); // check it!!!
        LOG( "DBWorker::createDB, query.exec",
             QString("Запит на видалення запису виконано успішно."), "" );
        refreshAllModels();
    }
    emit needRefresh();
}

bool DBWorker::editCurRecord(const int uniqId, const QString name, const int styleId, const QString com)
{
    if (mCurRec>=0)
    {
        QSqlQuery query(*mWorkDB);
        query.prepare(CHANGE_RECORD);
//        "CREATE TABLE IF NOT EXISTS lps (uniqId INTEGER PRIMARY KEY ASC, "
//            "caption text NOT NULL, styleId integer NOT NULL, comment text);"
//        "UPDATE lps caption=:caption, styleId=:styleId, comment=:comment WHERE uniqId=:uniqId"
        query.bindValue(":caption", name);
        query.bindValue(":styleId", styleId);
        query.bindValue(":comment", com);
        query.bindValue(":uniqId", uniqId);

        if(!query.exec())
        {
            LOG( "DBWorker::editCurRecord, query.exec",
                 QString("Проблема з виконанням запиту "
                         "<font face='DejaVu Sans Mono'>%1</font>.<br/>"
                         "Помилка: <font face='DejaVu Sans Mono'>%2</font>")
                 .arg(query.lastQuery())
                 .arg(query.lastError().text()), "" );
            return false;
        }
        query.clear();
        LOG( "DBWorker::editCurRecord, query.exec",
             QString("Запит виконано. Відредаговано запис <i>(%1, %2, %3, %4)</i>")
             .arg(uniqId)
             .arg(name)
             .arg(styleId)
             .arg(com), "" );

    }
    emit needRefresh();
    return true;
}


void DBWorker::search(const QString stext)
{
    if (mWorkDB != NULL)
    {
        if (stext.isEmpty())
        {
            LOG( "DBWorker::search", "Передано порожню стрічку", "" );
            return;
        }

        searchText = QString(SEARCH_LIKE).arg(stext);
        mTabModel->setQuery(searchText, *mWorkDB);

        mSearchRowsCount = mTabModel->rowCount();

        mTabModel->setupHeader();
        LOG( "DBWorker::search", searchText, "");
    }
}

int DBWorker::searchRowsCount() const
{
    return mSearchRowsCount;
}

bool DBWorker::isDbLoaded() const
{
    return mIsDbLoaded;
}

int DBWorker::findNextFreeId()
{
    int result = -1;
    QSqlQuery query(FIND_NEXT_FREE_ID, *mWorkDB);
    if(!query.exec())
    {
        LOG( "DBWorker::findNextFreeId, query.exec",
             QString("Проблема з виконанням запиту "
                     "<font face='DejaVu Sans Mono'>%1</font>.<br/>"
                     "Помилка: <font face='DejaVu Sans Mono'>%2</font>")
             .arg(query.lastQuery())
             .arg(query.lastError().text()), "" );
        return result;
    }
    query.next();

    bool converted = false;
    result = query.value(0).toInt(&converted);
    if (converted)
    {
        query.clear();
        LOG( "DBWorker::findNextFreeId, query.exec",
             QString("Запит виконано. Отримано результат: %1").arg(result), "" );
    }
    else
    {
        LOG( "DBWorker::findNextFreeId, query.exec",
             "Запит виконано. Отримано некоректний результат!", "" );
        result = -1;
    }
    return result;
}

void DBWorker::refreshAllModels()
{
    mTabModel->refresh();
    mTreeModel->refresh();
}

bool DBWorker::insertRecord(const int uniqId, const QString name,
                            const int styleId, const QString com, bool doRefresh)
{
    QSqlQuery query(*mWorkDB);
    query.prepare(INSERT_RECORD);
    query.bindValue(":uniqId", uniqId);
    query.bindValue(":caption", name);
    query.bindValue(":styleId", styleId);
    query.bindValue(":comment", com);

    if(!query.exec())
    {
        LOG( "DBWorker::insertRecord, query.exec",
             QString("Проблема з виконанням запиту "
                     "<font face='DejaVu Sans Mono'>%1</font>.<br/>"
                     "Помилка: <font face='DejaVu Sans Mono'>%2</font>")
             .arg(query.lastQuery())
             .arg(query.lastError().text()), "" );
        return false;
    }
    query.clear();
    LOG( "DBWorker::insertRecord, query.exec",
         QString("Запит виконано. Додано новий запис <i>(%1, %2, %3, %4)</i>")
         .arg(uniqId)
         .arg(name)
         .arg(styleId)
        .arg(com), "" );

//    if (doRefresh) emit needRefresh();
    return true;
}

bool DBWorker::batchInsertRecords(QVariantList uniqIds,
                                  QVariantList names,
                                  QVariantList styleIds,
                                  QVariantList comments)
{
    QSqlQuery query(*mWorkDB);
    query.prepare(INSERT_RECORD);
    query.addBindValue(uniqIds);
    query.addBindValue(names);
    query.addBindValue(styleIds);
    query.addBindValue(comments);

    if (!query.execBatch())
    {
        LOG( "DBWorker::batchInsertRecords",
             "Не вдалося додати записи в БД режимі batch",
             query.lastError().text());
        return false;
    }

    return true;
}

bool DBWorker::getRecordByUniqId(const int uniqId,
                                 QString &name,
                                 int &styleId,
                                 QString &comment)
{
  QSqlQuery q(*mWorkDB);

  q.prepare(GET_RECORD_BY_UNIQID);
  q.bindValue(":uniqId", uniqId);
  if (q.exec())
    {
      q.next();
      name = q.value(1).toString();
      styleId = q.value(2).toInt();
      comment = q.value(3).toString();
      return true;
    }
  return false;
}

void DBWorker::freeModels()
{ // freeing models if any
    if (mTabModel!=NULL)
    {
        delete mTabModel;
        mTabModel = NULL;
    }
    if (mTreeModel!=NULL)
    {
        delete mTreeModel;
        mTreeModel = NULL;
    }
}

void DBWorker::createModels()
{
    mTabModel  = new MyTabModel(this);
    mTabModel->setupHeader();

    mTreeModel = new TreeModel(this);

//    connect(mTabModel, SIGNAL(needReloadData()),
//            appManager->mainWindow(), SLOT(refreshViews()));

    connect(mTreeModel, SIGNAL(needReloadData()),
            appManager->mainWindow(), SLOT(refreshViews()));


    mTreeModel->setupModelData();
}
